package com.cat.orm.core.db.repository;

import com.cat.orm.core.base.BasePo;
import com.cat.orm.core.db.repository.dao.DefaultDao;
import com.cat.orm.core.db.repository.dao.IBaseDao;
import com.github.benmanes.caffeine.cache.AsyncCache;
import com.github.benmanes.caffeine.cache.Caffeine;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.TimeUnit;

/**
 * 异步的仓库
 * @author Jeremy Feng
 * @date 2024/9/7 14:16
 */
public class AsyncRepository<V extends BasePo> {

    private final static String ALL_DATA = "all_data";

    /**
     * key: 主键
     * value: 存储实体
     */
    private final AsyncCache<Object, V> cache;

    /**
     * key: 主键
     * value: 存储实体
     */
    private final AsyncCache<String, List<V>> indexCache;

    private final IBaseDao<V> dao;

    /**
     * 外部可以指定dao, 由开发者控制dao实现
     */
    public AsyncRepository(IBaseDao<V> dao) {
        this.dao = dao;
        this.cache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)  // 缓存过期时间
                .maximumSize(10_000)  // 最大缓存条目数
                .buildAsync();
        this.indexCache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)  // 缓存过期时间
                .maximumSize(10_000)  // 最大缓存条目数
                .buildAsync();
    }

    /**
     * 外部不指定dao, 使用默认dao
     */
    public AsyncRepository(JdbcTemplate jdbcTemplate) {
        this.dao = new DefaultDao<V>(jdbcTemplate);
        this.cache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)  // 缓存过期时间
                .maximumSize(10_000)  // 最大缓存条目数
                .buildAsync();
        this.indexCache = Caffeine.newBuilder()
                .expireAfterWrite(10, TimeUnit.MINUTES)  // 缓存过期时间
                .maximumSize(10_000)  // 最大缓存条目数
                .buildAsync();
    }

    /**
     * 通过类对象, 查询复合条件的数据信息
     * @date 2020年6月30日
     * @return 异步结果返回
     */
    public CompletableFuture<V> selectByPrimaryKey(Object key){
        return cache.get(key, dao::selectByKey);
    }

    /**
     * 查询所有, 查询出来的同步缓存到cache
     * @date 2020年6月30日
     * @return 异步结果返回
     */
    public CompletableFuture<List<V>> selectAll(){
        return indexCache.get(ALL_DATA, k->{
            List<V> ret = dao.selectAll();
            ret.forEach(c-> cache.put(c.key(), CompletableFuture.completedFuture(c)));
            return ret;
        });
    }

    /**
     * 查询玩家信息, 通过默认索引,这种方式的实现, 默认直接获取缓存的sql进行查询
     * @date 2020年6月30日
     * @return 异步结果返回
     */
    public CompletableFuture<List<V>> selectByIndex(Object[] objs){
        String indexString = Arrays.toString(objs);
        return indexCache.get(indexString, k-> {
            List<V> ret = dao.selectByIndex(objs);
            for (V v : ret) {
                Object key = v.key();
                if (key == null){
                    continue;
                }
                //如果主键缓存不存在, 则更新到主键缓存
                cache.put(key, CompletableFuture.completedFuture(v));
            }
            return ret;
        });
    }

    /**
     * 通过指定字段查询数据,这种方式只能通过sql组装进行查询
     * @date 2020年6月30日
     * @return 异步结果返回
     */
    public CompletableFuture<List<V>> selectByIndex(String[] props, Object[] objs){
        String indexString = Arrays.toString(objs);
        return indexCache.get(indexString, k-> {
            List<V> ret = dao.selectByIndex(props, objs);
            for (V v : ret) {
                Object key = v.key();
                if (key == null){
                    continue;
                }
                cache.put(key, CompletableFuture.completedFuture(v));
            }
            return ret;
        });
    }

    /**
     * 添加玩家信息. 如果有主键, 更新主键缓存. 如有索引缓存也需要更新.
     * @date 2020年6月30日
     * @param po 插入对象
     */
    public CompletableFuture<Integer> insert(V po){
        return CompletableFuture.supplyAsync(()->{
            this.cacheUpdate(po);
            return dao.insert(po);
        });
    }

    /**
     * 添加数据信息
     * @date 2020年6月30日
     * @param po 替换对象
     */
    public CompletableFuture<Integer> replace(V po){
        return CompletableFuture.supplyAsync(()->{
            this.cacheUpdate(po);
            return dao.replace(po);
        });
    }

    /**
     * 修改数据
     * @date 2020年6月30日
     * @param po 要修改对象
     */
    public CompletableFuture<Integer> update(V po){
        return CompletableFuture.supplyAsync(()->{
            this.cacheUpdate(po);
            return dao.update(po);
        });
    }

    /**
     * 批量添加, 更新主键缓存, 索引缓存无效
     *
     * @date 2020年6月30日
     * @param basePos 要保存集合
     */
    public CompletableFuture<int[]> insertBatch(Collection<V> basePos){
        return CompletableFuture.supplyAsync(()->{
            for (V po : basePos) {
                this.cacheUpdate(po);
            }
            return dao.insertBatch(basePos);
        });
    }

    /**
     * 批量修改玩家信息, 实现默认数据分类
     * @date 2020年6月30日
     * @param basePos 要修改的集合
     */
    public CompletableFuture<int[]> updateBatch(Collection<V> basePos){
        return CompletableFuture.supplyAsync(()->{
            for (V po : basePos) {
                this.cacheUpdate(po);
            }
            return dao.insertBatch(basePos);
        });
    }

    /**
     * 删掉数据
     * @date 2020年6月30日
     * @param po 删除的对象
     */
    public CompletableFuture<Integer> delete(V po){
        return CompletableFuture.supplyAsync(()->{
            this.cacheDelete(po);
            return dao.delete(po);
        });
    }

    /**
     * 删除所有, 复合类对象信息, 全部删除
     * @date 2020年6月30日
     */
    public CompletableFuture<Integer> deleteAll(){
        return CompletableFuture.supplyAsync(()->{
            cache.synchronous().invalidateAll();
            indexCache.synchronous().invalidateAll();
            return dao.deleteAll();
        });
    }

    /**
     * 批量删除, 批量删除指定集合内的数据信息
     * @date 2020年6月30日
     * @param basePos 数据集合
     */
    public CompletableFuture<int[]> deleteBatch(Collection<V> basePos){
        return CompletableFuture.supplyAsync(()->{
            for (V basePo : basePos) {
              this.cacheDelete(basePo);
            }
            return dao.deleteBatch(basePos);
        });
    }

    /**
     * 缓存更新
     * @param po 缓存更新
     */
    private void cacheUpdate(V po){
        //主键不为null, 更新主键缓存
        Object key = po.key();
        if (key != null){
            cache.put(key, CompletableFuture.completedFuture(po));
        }
        //如果索引缓存有数据, 使索引缓存无效
        Object[] indexValues = po.keyAndIndexValues();
        if (indexValues.length > 0){
            String indexString = Arrays.toString(indexValues);
            indexCache.synchronous().invalidate(indexString);
        }
    }

    /**
     * 缓存删除对象
     * @param po 缓存更新
     */
    private void cacheDelete(V po){
        //主键不为null, 更新主键缓存
        Object key = po.key();
        if (key != null){
            cache.synchronous().invalidate(key);
        }
        //如果索引缓存有数据, 使索引缓存无效
        Object[] indexValues = po.keyAndIndexValues();
        if (indexValues.length > 0){
            String indexString = Arrays.toString(indexValues);
            indexCache.synchronous().invalidate(indexString);
        }
    }


}
